package di.module;

import android.text.TextUtils;
import android.widget.Toast;

import com.f2prateek.rx.preferences2.RxSharedPreferences;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.xgggh.redpack.BuildConfig;
import com.xgggh.redpack.domain.app.Constant;
import com.xgggh.redpack.domain.auth.Auth;
import com.xgggh.redpack.utils.AuthManager;

import net.http.HttpAgent;
import net.http.LiveNetworkMonitor;
import net.http.NetworkMonitor;
import net.http.NoNetworkException;
import net.http.SSLSocketClient;
import net.http.adapter.NullStringToEmptyAdapterFactory;

import java.io.IOException;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.inject.Named;
import javax.inject.Singleton;

import app.OkApplication;
import dagger.Module;
import dagger.Provides;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Authenticator;
import okhttp3.Cache;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.Credentials;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.Route;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.converter.scalars.ScalarsConverterFactory;
import retrofit2.mock.MockRetrofit;
import retrofit2.mock.NetworkBehavior;

@Module
public  class NetWorkModule {



    @Provides
    @Singleton
    public static Cache provideCache(OkApplication context) {
        int cacheSize = 10 * 1024 * 1024; // 10 MiB
        Cache cache  = new Cache(context.getCacheDir(), cacheSize);
        return cache;
    }
    @Provides
    //@Singleton
    static Retrofit provideRetrofit(@Named("authorizeHttpClient")OkHttpClient okHttpClient,
                                    Gson gson,
                                    @Named("domain") String domain) {
        return new Retrofit.Builder()
                .baseUrl(domain)
                .client(okHttpClient)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .addConverterFactory(ScalarsConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
                .build();
    }
    @Provides
    @Singleton
    static Gson provideGoogleSon(){
        Gson gson = new GsonBuilder()
                .registerTypeAdapterFactory(new NullStringToEmptyAdapterFactory<>())
                .create();
        return gson;
    }


    @Provides
    @Singleton
    static MockRetrofit provideMockRetrofit(Retrofit retrofit) {
        NetworkBehavior behavior = NetworkBehavior.create();
        MockRetrofit mockRetrofit = new MockRetrofit.Builder(retrofit)
                .networkBehavior(behavior)
                .build();
        return mockRetrofit;
    }

    @Provides
    @Named("authorizeHttpClient")
    static  OkHttpClient provideAuthorizeHttpClient(OkHttpClient okHttpClient
            ,@Named("tokenAgentInterceptor")Interceptor tokenAgentInterceptor) {
        return okHttpClient.newBuilder().addInterceptor(tokenAgentInterceptor).build();
    }

    @Provides
    @Singleton
    static  OkHttpClient provideOkHttpClient(Cache cache
                                     ,OkApplication context
            ,final NetworkMonitor networkMonitor) {
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .authenticator(new Authenticator() {
                    @Override
                    public Request authenticate(Route route, Response response) throws IOException {
                        String credential = Credentials.basic("client", "secret");
                        return response.request().newBuilder()
                                .header("Authorization", credential)
                                .build();
                    }
                })
                .connectTimeout(15, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .readTimeout(30, TimeUnit.SECONDS)
                .cache(cache)
                .sslSocketFactory(SSLSocketClient.getSSLSocketFactory())
                .hostnameVerifier(SSLSocketClient.getHostnameVerifier())

                //还可以设置某一个接口不用代理
               /* .proxySelector(new ProxySelector() {
                    @Override
                    public List<Proxy> select(URI uri) {
                        return Collections.singletonList(Proxy.NO_PROXY);
                    }

                    @Override
                    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {

                    }
                })*/
                //.cookieJar(new LocalCookieJar())
                .addInterceptor(new Interceptor() {
                    @Override
                    public Response intercept(Chain chain) throws IOException {
                        boolean connected = networkMonitor.isConnected();
                        if (connected) {
                            try{
                                return chain.proceed(chain.request());
                            }catch (IOException e){
                                Observable.just(0)
                                        .observeOn(AndroidSchedulers.mainThread())
                                        .subscribe(new Consumer<Integer>() {
                                            @Override
                                            public void accept(Integer integer) throws Exception {
                                                Toast.makeText(context, e.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
                                            }
                                        });
                                throw new NoNetworkException(e.getMessage());
                            }
                        } else {
                            Observable.just(0)
                                    .observeOn(AndroidSchedulers.mainThread())
                                    .subscribe(new Consumer<Integer>() {
                                        @Override
                                        public void accept(Integer integer) throws Exception {
                                            Toast.makeText(context, "无网络连接", Toast.LENGTH_SHORT).show();
                                        }
                                    });
                            throw new NoNetworkException("无网络连接");
                        }
                    }
                })
                //.addInterceptor(new HttpLoggingInterceptor().setLevel(BuildConfig.DEBUG? HttpLoggingInterceptor.Level.BODY: HttpLoggingInterceptor.Level.NONE))
                ;
        if (!BuildConfig.DEBUG){
            builder.proxy(Proxy.NO_PROXY); //不使用socket代理请求
        }
        return builder.build();
    }



    @Provides
   //@Singleton 每次都要检查
    static NetworkMonitor provideNetworkMonitor(OkApplication context) {
        return new LiveNetworkMonitor(context);
    }

    @Provides
    @Singleton
    @Named("userAgent")
    static String provideUserAgent(OkApplication context) {
        return HttpAgent.getUserAgent(context);
    }

    @Provides
    //@Singleton  每次都要检查下token
    @Named("tokenAgentInterceptor")
    Interceptor provideTokenAgentInterceptor(final @Named("userAgent") String userAgent,final Auth auth) {
        return chain -> {
            Request originalRequest = chain.request();
            Request.Builder requestBuilder = originalRequest.newBuilder();
            if (!TextUtils.isEmpty(auth.getAccessToken())){
                requestBuilder.header("Authorization", "Bearer "+auth.getAccessToken());
            }
            //User-Agent: okhttp/3.8.0
            requestBuilder.header("User-Agent",userAgent);
            requestBuilder.header("Content-Type", "application/json;charset=UTF-8");
            requestBuilder.header("Connection","close");
            return chain.proceed(requestBuilder.build());
        };
    }

    /*@Provides
    @Singleton
    ClearableCookieJar provideCookieJar(OkApplication application) {
        ClearableCookieJar cookieJar =
                new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(application));
        return cookieJar;
    }*/

    //CookieJar是用于保存Cookie的
    class LocalCookieJar implements CookieJar {
        List<Cookie> cookies;
        @Override
        public List<Cookie> loadForRequest(HttpUrl arg0) {
            if (cookies != null)
                return cookies;
            return new ArrayList<Cookie>();
        }

        @Override
        public void saveFromResponse(HttpUrl arg0, List<Cookie> cookies) {
            this.cookies = cookies;
        }

    }

    @Provides
    @Singleton
    @Named("domain")
    static String  providesDomain() {
        return BuildConfig.domain;
    }
}
